package com.gitee.wsl.ext.array

import com.gitee.wsl.ext.collection.loop


/**
 * For each implementation with start and end.
 * @param start starting index
 * @param end ending index
 */
inline fun <T> Array<out T>.forEach(start: Int, end: Int = this.size, action: (T) -> Unit) {
    var index = start
    while (index < end) {
        action(this[index])
        index++
    }
}

/**
 * For each indexed implementation with start and end.
 * @param start starting index
 * @param end ending index
 */
inline fun <T> Array<out T>.forEachIndexed(start: Int, end: Int = this.size, action: (index: Int, T) -> Unit) {
    var index = start
    while (index < end) {
        action(index, this[index])
        index++
    }
}

/**
 * For each reversed implementation with from and to.
 * @param from starting index
 * @param to ending index
 */
 inline fun <T> Array<T>.forEachReverse(
    from: Int = lastIndex,
    to: Int = 0,
    action: (T) -> Unit,
) {
    var index = from
    while (index >= to) {
        action(this[index])
        index--
    }
}

/**
 * For each reversed indexed implementation with from and to.
 * @param from starting index
 * @param to ending index
 */
 inline fun <T> Array<T>.forEachReverseIndexed(
    from: Int = lastIndex,
    to: Int = 0,
    action: (T, index: Int) -> Unit,
) {
    var index = from
    while (index >= to) {
        action(this[index], index)
        index--
    }
}

/**
 * For each reversed indexed implementation with from and to.
 * @param from starting index
 * @param to ending index
 */
 inline fun IntArray.forEachReverseIndexed(
    from: Int = lastIndex,
    to: Int = 0,
    action: (Int, index: Int) -> Unit,
) {
    var index = from
    while (index >= to) {
        action(this[index], index)
        index--
    }
}

/**
 * Executes splits array with standard partition (that used in quicksort) in ascending order
 * @param start index from (inclusive)
 * @param end index to (inclusive)
 * @return index of split (to the left, elements are less than or equal, to the right, elements are greater)
 */
fun <T : Comparable<T>> Array<T>.partitionAscending(start: Int, end: Int): Int {
    val pivot = get(end)
    var i = start

    loop(start = start, end = end) { j ->
        // If the current element is less than or equal to the pivot
        if (get(j) <= pivot) {
            // Swap the current element with the element at the temporary pivot index
            swap( i, j)
            // Move the temporary pivot index forward
            ++i
        }
    }

    // Swap the pivot with the last element
    swap(i, end)
    return i // the pivot index
}

/**
 * Executes splits array with standard partition (that used in quicksort) in descending order
 * @param start index from (inclusive)
 * @param end index to (inclusive)
 * @return index of split (to the left, elements are less than or equal, to the right, elements are greater)
 */
 fun <T : Comparable<T>> Array<T>.partitionDescending(start: Int, end: Int): Int {
    val pivot = get(end)
    var i = start

    loop(start = start, end = end) { j ->
        // If the current element is less than or equal to the pivot
        if (get(j) >= pivot) {
            // Swap the current element with the element at the temporary pivot index
            swap( i,  j)
            // Move the temporary pivot index forward
            ++i
        }
    }

    // Swap the pivot with the last element
    swap(i, end)
    return i // the pivot index
}